/**
 * 
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 * 
 *   http://www.apache.org/licenses/LICENSE-2.0
 *   
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 * 
 */
package org.jiopi.ibean.kernel.config;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import org.jiopi.ibean.share.ShareUtil.IOUtil;


/**
 * 
 * data model of a module's annotations
 * 
 * @since 2010.5.12
 *
 */
public class ModuleAnnotations {
	
	/**
	 * key is package name,value is reset method name
	 */
	private HashMap<String,String> hotswaps = new HashMap<String,String>();
	
	public HashMap<String,ControlPanel> controlPanels = new HashMap<String,ControlPanel>();
	
	private ModuleAnnotations(){
	}
	public static ModuleAnnotations createModuleAnnotations(File moduleXmlFile) throws FileNotFoundException, DocumentException{
		InputStream is = null;
		try{
			is = new BufferedInputStream(new FileInputStream(moduleXmlFile));
			return createModuleAnnotations(is);
		}finally{
			IOUtil.close(is);
		}
	}
	
	@SuppressWarnings("unchecked")
	public static ModuleAnnotations createModuleAnnotations(InputStream is) throws DocumentException{
		SAXReader reader = new SAXReader();
		Document doc = reader.read(is);
		ModuleAnnotations ma = new ModuleAnnotations();
		Element moduleElement = doc.getRootElement();
		
		Element hotswapElement = moduleElement.element("moduleElement");
		if(hotswapElement!=null){
			Iterator<Element> hotswapClasses = hotswapElement.elementIterator("class");
			while(hotswapClasses.hasNext()){
				Element hotswapClasse = hotswapClasses.next();
				String resetMethod = hotswapClasse.attributeValue("reset-method");
				if(resetMethod==null)resetMethod="";
				String packages = hotswapClasse.getTextTrim();
				ma.hotswaps.put(packages, resetMethod);
			}
		}
		
		
		Iterator<Element> controlpanelElements = moduleElement.elementIterator("controlpanel");
		while(controlpanelElements.hasNext()){
			Element controlpanelElement = controlpanelElements.next();
			String className = controlpanelElement.attributeValue("class");
			ControlPanel cp = new ControlPanel();
			ma.controlPanels.put(className, cp);
			
			String registerModule = controlpanelElement.attributeValue("register-module");
			if("true".equals(registerModule)) cp.registerControlpanel = true;
			
			Element registerControlpanels = controlpanelElement.element("register-controlpanels");
			if(registerControlpanels!=null){
				Iterator<Element> controlpanelClasses = registerControlpanels.elementIterator("class");
				while(controlpanelClasses.hasNext()){
					Element controlpanelClass = controlpanelClasses.next();
					String classname = controlpanelClass.getTextTrim();
					cp.registerControlpanels.add(classname);
				}
			}
			
			Element instantiationElement = controlpanelElement.element("instantiation");
			if(instantiationElement!=null){
				String initMethod = null;
				String instancetype = null;
				String factoryMethod = null;
				
				Element initMethodElement = instantiationElement.element("init-method");
				Element instancetypeElement = instantiationElement.element("instancetype");
				Element factoryMethodElement = instantiationElement.element("factory-method");
				
				if(initMethodElement!=null)initMethod=initMethodElement.getTextTrim();
				if(instancetypeElement!=null)instancetype=instancetypeElement.getTextTrim();
				if(factoryMethodElement!=null)factoryMethod=factoryMethodElement.getTextTrim();
				ControlPanel.Instantiation instantiation = new ControlPanel.Instantiation(instancetype,factoryMethod,initMethod);
				
				cp.instantiation = instantiation;
			}
			
			Iterator<Element> socketModuleElements = controlpanelElement.elementIterator("socket-module");
			while(socketModuleElements.hasNext()){
				Element socketModuleElement = socketModuleElements.next();
				String varName = socketModuleElement.getTextTrim();
				HashMap<String,String> config = new HashMap<String,String>();
				String id = socketModuleElement.attributeValue("id");
				String module = socketModuleElement.attributeValue("module");
				String version = socketModuleElement.attributeValue("version");
				String configuration = socketModuleElement.attributeValue("configuration");
				if(id!=null)config.put("id", id);
				if(module!=null)config.put("module", module);
				if(version!=null)config.put("version", version);
				if(configuration!=null)config.put("configuration", configuration);
				cp.socketModule.put(varName, config);
			}
			
			Iterator<Element> socketControlPanelElements = controlpanelElement.elementIterator("socket-controlpanel");
			while(socketControlPanelElements.hasNext()){
				Element socketControlPanelElement = socketControlPanelElements.next();
				String varName = socketControlPanelElement.getTextTrim();
				HashMap<String,String> config = new HashMap<String,String>();
				String id = socketControlPanelElement.attributeValue("id");
				String module = socketControlPanelElement.attributeValue("module");
				String version = socketControlPanelElement.attributeValue("version");
				String controlpanel = socketControlPanelElement.attributeValue("controlpanel");
				String configuration = socketControlPanelElement.attributeValue("configuration");
				if(id!=null)config.put("id", id);
				if(module!=null)config.put("module", module);
				if(version!=null)config.put("version", version);
				if(controlpanel!=null)config.put("controlpanel", controlpanel);
				if(configuration!=null)config.put("configuration", configuration);
				cp.socketControlpanel.put(varName, config);
			}
			
			Iterator<Element> methodElements = controlpanelElement.elementIterator("method");
			while(methodElements.hasNext()){
				Element methodElement = methodElements.next();
				StringBuilder methodName = new StringBuilder(methodElement.attributeValue("name"));
				Element parametersElement = methodElement.element("parameters");
				Iterator<Element> parameterElements = parametersElement.elementIterator("parameter");
				ArrayList<HashMap<String,String>> parameterAnnos = new ArrayList<HashMap<String,String>>();
				while(parameterElements.hasNext()){
					Element parameterElement = parameterElements.next();
					methodName.append(",").append(parameterElement.attributeValue("class"));
					String reference = parameterElement.attributeValue("reference");
					if("true".equals(reference)){
						HashMap<String,String> annos = new HashMap<String,String>();
						annos.put("reference", reference);
						parameterAnnos.add(annos);
					}else{
						parameterAnnos.add(null);
					}
				}
				cp.methods.put(methodName.toString(), parameterAnnos);
			}
			
			ma.controlPanels.put(className, cp);
		}
		
		return ma;
	}
	
	
	
	public static class ControlPanel{
		public boolean registerControlpanel = false;
		public final HashSet<String> registerControlpanels = new HashSet<String>();
		
		public Instantiation instantiation = null;
		
		public HashMap<String,HashMap<String,String>> socketModule = new HashMap<String,HashMap<String,String>>();
		public HashMap<String,HashMap<String,String>> socketControlpanel = new HashMap<String,HashMap<String,String>>();
		public HashMap<String,ArrayList<HashMap<String,String>>> methods = new HashMap<String,ArrayList<HashMap<String,String>>>();
		
		public static class Instantiation{
			public final String instancetype;
			public final String factoryMethod;
			public final String initMethod;
			
			private Instantiation(String instancetype,String factoryMethod,String initMethod){
				this.instancetype = instancetype;
				this.factoryMethod = factoryMethod;
				this.initMethod = initMethod;
			}
			
		}
	}
	
	

}
